const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

const isProduction = process.env.NODE_ENV === 'production';

// 代理日志
const proxyLog = {
  onProxyReq: (proxyReq, req, res) => {
    console.log(
      `[WEBPACK PROXY] Proxying ${req.method} ${req.url} -> ${proxyReq.protocol}//${proxyReq.host}${proxyReq.path}`
    );
  },
  onProxyRes: (proxyRes, req, res) => {
    console.log(
      `[WEBPACK PROXY] Received response for ${req.url} with status ${proxyRes.statusCode}`
    );
  },
};

module.exports = {
  // ==================== 模式 ====================
  mode: isProduction ? 'production' : 'development',

  // ==================== 入口文件 ====================
  entry: './src/index.tsx', // 应用的主入口文件

  // ==================== 输出配置 ====================
  output: {
    path: path.resolve(__dirname, 'dist'), // 打包输出目录
    filename: '[name].[contenthash:8].js', // 主包文件名，含 8 位内容哈希
    chunkFilename: '[name].[contenthash:8].chunk.js', // 动态导入的 chunk 文件名
    clean: true, // 构建前清空 dist 目录（Webpack 5+ 内置）
  },

  // ==================== 缓存优化 ====================
  cache: {
    type: 'filesystem', // 使用文件系统缓存
    cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'), // 缓存路径
    buildDependencies: {
      config: [__filename], // 当 webpack 配置文件变化时，缓存失效
    },
  },

  // ==================== 模块解析 ====================
  resolve: {
    extensions: ['.tsx', '.ts', '.js'], // 自动解析这些后缀的文件
    alias: {
      '@': path.resolve(__dirname, 'src'), // 路径别名 @ 指向 src
      '@test': path.resolve(__dirname, 'src/modules/test'), // @test 指向测试模块
    },
    mainFields: ['esmodule', 'module', 'main'], // 优先使用 ES 模块字段
  },

  // ==================== 模块规则（加载器） ====================
  module: {
    rules: [
      // TypeScript/TSX 文件使用 babel-loader 处理
      {
        test: /\.(ts|tsx)$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true, // 启用 babel 编译缓存
            cacheCompression: false, // 不压缩缓存文件，提升读取速度
          },
        },
      },
      // CSS 文件：生产用 MiniCssExtractPlugin，开发用 style-loader
      {
        test: /\.css$/,
        use: [
          isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
          'css-loader',
        ],
      },
      // SCSS/SASS 文件：同上，额外使用 sass-loader
      {
        test: /\.s[ac]ss$/i,
        use: [
          isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
          'css-loader',
          'sass-loader',
        ],
      },
      // 图片资源：使用 asset/resource 输出到 images/ 目录
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'images/[hash][ext][query]',
        },
      },
      // 字体文件：输出到 fonts/ 目录
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'fonts/[hash][ext][query]',
        },
      },
    ],
  },

  // ==================== 代码分割与优化 ====================
  optimization: {
    splitChunks: {
      chunks: 'all', // 对所有 chunk 进行分割
      cacheGroups: {
        // 第三方库打包
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
          priority: 10,
        },
        // React 相关单独打包（更高优先级）
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)/,
          name: 'react',
          chunks: 'all',
          priority: 20,
        },
        // 公共模块打包（被引用 ≥2 次）
        common: {
          name: 'common',
          chunks: 'all',
          minChunks: 2,
          enforce: true, // 强制打包，忽略 minSize 等限制
          priority: 5,
        },
      },
    },
    runtimeChunk: 'single', // 将 webpack 运行时提取为单独文件
    minimize: isProduction, // 生产环境开启压缩
    minimizer: [
      // 使用 esbuild 快速压缩 JS（比 Terser 快很多）
      new TerserPlugin({
        minify: TerserPlugin.esbuildMinify,
        terserOptions: {
          target: 'es2015', // 压缩目标语法
        },
      }),
      // 压缩 CSS
      new CssMinimizerPlugin(),
    ],
  },

  // ==================== 插件 ====================
  plugins: [
    // 生成 index.html 并自动注入打包资源
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),

    // 生产环境专用插件
    ...(isProduction
      ? [
          // 提取 CSS 到单独文件
          new MiniCssExtractPlugin({
            filename: '[name].[contenthash:8].css',
            chunkFilename: '[name].[contenthash:8].chunk.css',
          }),

          // 生成 gzip 压缩文件，用于 Nginx 开启 gzip
          new CompressionPlugin({
            algorithm: 'gzip',
            test: /\.(js|css|html|svg)$/, // 压缩这些文件
            threshold: 8192, // 大于 8KB 才压缩
            deleteOriginalAssets: false, // 不删除原文件
          }),

          // 图片压缩（构建时）
          new ImageMinimizerPlugin({
            minimizer: {
              implementation: ImageMinimizerPlugin.imageminMinify,
              options: {
                plugins: [
                  ['gifsicle', { interlaced: true }],
                  ['jpegtran', { progressive: true }],
                  ['optipng', { optimizationLevel: 5 }],
                  [
                    'svgo',
                    { plugins: [{ name: 'preset-default', params: {} }] },
                  ],
                ],
              },
            },
          }),
        ]
      : []), // 开发环境不启用
  ],

  // ==================== 开发服务器 ====================
  devServer: {
    static: {
      directory: path.join(__dirname, 'dist'), // 静态资源目录
    },
    historyApiFallback: true, // 支持 SPA 路由（如 /about 不返回 404）
    hot: true, // 启用热更新（HMR）
    port: 5000, // 开发服务器端口
    open: true, // 启动时自动打开浏览器
    proxy: [
      {
        context: ['/api'], // 代理 /test 开头的请求
        target: 'http://localhost:3000/', // 代理到后端服务
        changeOrigin: true, // 修改请求头中的 origin
        pathRewrite: {
          '^/api': '', // 重写路径，去掉 /test 前缀
        },
        ...proxyLog, // 可能是自定义日志配置
      },
    ],
    watchFiles: ['src/**/*', 'public/**/*'], // 监听这些文件变化
    devMiddleware: {
      writeToDisk: false, // 不将文件写入磁盘（只在内存中）
    },
    client: {
      logging: 'info', // 控制台日志级别
    },
  },

  // ==================== Source Map ====================
  devtool: isProduction
    ? 'nosources-source-map' // 生产：有堆栈追踪，但不暴露源码
    : 'eval-cheap-module-source-map', // 开发：快 + 定位准确
};
